#pragma once

namespace Object
{
	struct Base;
}

template<typename T, typename... Args>
Object::Base* makeObject(Args&&... args);

namespace Object
{
	using Map = std::unordered_map<size_t, Base*>;
	using Cld = std::unordered_map<std::type_index, Map>;
	template <typename T>
	struct BaseT;

	struct Base
	{
		Base* _pParent = nullptr;
		std::type_index _ty;
		size_t _id = 0;

		Cld _cld;

		Base(const type_info& info) : _ty(std::type_index(info)) {}
		virtual ~Base();
		virtual auto init()->bool { return true; }
		virtual auto fillOs(std::ostream& os) const->std::ostream&;
		virtual auto fillSelfOs(std::ostream& os) const->std::ostream&;
		virtual auto fillChildenOs(std::ostream& os) const->std::ostream&;

		template <typename T, typename... Args>
		auto create(size_t id, Args&&... args)->BaseT<T>*;
		template <typename T, typename... Args>
		auto emplace(size_t id, Args&&... args)->BaseT<T>*;
		template <typename T>
		auto get(size_t id)->BaseT<T>*;
		auto get(std::type_index ty, size_t id) const->const Base*;
		template <typename T>
		auto getCld()->Map*;
		template <typename T>
		auto getCld() const->const Map*;
		template <typename T>
		auto clear(size_t id)->bool;

	private:
		auto initCallback()->bool;
		template<typename Define, typename Data>
		auto initComponent()->void;

	};


	template <typename T>
	struct BaseT : public Base
	{
		BaseT() : Base(typeid(T)) {}
	};

	namespace Component
	{
		namespace FillOs
		{
			struct Define : public BaseT<Define>, public ::Component::DefineBase
			{
				using Base = ::Component::DefineBase;

				uint8_t _format = 0;
				char _separator = 0;

				Define(uint8_t format = 0, char separator = ',', size_t order = 100);
			};

			struct Data : public BaseT <Data>, public ::Component::DataBase
			{
			};
		}
	}



	namespace Detail
	{
		template <typename T>
		struct Create
		{
			template <typename... Args>
			BaseT<T>* operator() (Args&&... args);
		};
	}
}

#include "BaseObject.h"
#include "ObjectImpl.h"
